﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MetaCollection.Framework.Model;
using MetaCollection.ContentService.Http;
using MetaCollection.Framework;

namespace MetaCollection.ContentService.WebDav.Methods
{
	public static class MakeCollection
	{
		/// <summary>
		/// MKCOL creates a new collection resource at the location specified by the Request-URI. If
		/// the Request-URI is already mapped to a resource, then the MKCOL MUST fail. During MKCOL
		/// processing, a server MUST make the Request-URI an internal member of its parent collection,
		/// unless the Request-URI is "/". If no such ancestor exists, the method MUST fail. When
		/// the MKCOL operation creates a new collection resource, all ancestors MUST already exist,
		/// or the method MUST fail with a 409 (Conflict) status code. For example, if a request to
		/// create collection /a/b/c/d/ is made, and /a/b/c/ does not exist, the request must fail.
		/// 
		/// If MKCOL is invoked with a request body the 415 Unsupported Media code should be returned.
		/// 
		/// Supported Status Codes are:
		///   - 201 (Created) - The collection was created. 
		///   - 403 (Forbidden) - This indicates at least one of two conditions: 
		///       1) the server does not allow the creation of collections at the given location 
		///       in its URL namespace, or 
		///       2) the parent collection of the Request-URI exists but cannot accept members.
		///   - 405 (Method Not Allowed) - MKCOL can only be executed on an unmapped URL.
		///   - 409 (Conflict) - A collection cannot be made at the Request-URI until one or more
		///     intermediate collections have been created. The server MUST NOT create those
		///     intermediate collections automatically.
		///   - 415 (Unsupported Media Type) - The server does not support the request body type
		///   - 507 (Insufficient Storage) 
		/// </summary>
		/// <param name="context">The http request/response context.</param>
		/// <param name="handler">The metacollection item request handler.</param>
		/// <remarks>Responses to this method must not be cached</remarks>
		public static void Respond(DavContext context, IRequestHandler handler)
		{
			// item may not exist already.
			IItemInstance item = context.Item as IItemInstance;
			Uri itemUri = context.Request.Url.ToCollectionUri();
			if (item != null)
				throw new Http.ClientException(ClientErrorStatus.MethodNotAllowed);
			// parent must exist.
			Uri parentUri = new Uri(itemUri.AbsoluteUri.Substring(0, itemUri.AbsoluteUri.LastIndexOf('/')));
			IItemInstance parentItem = handler.ItemRequest(context.User, RequestTypes.GetItem, parentUri, LoadOptions.ItemReference).FirstOrDefault();
			if (parentItem == null)
				throw new Http.ClientException(ClientErrorStatus.Conflict);
			// content is not allowed
			if (context.Request.Xml != null)
				throw new Http.ClientException(ClientErrorStatus.UnsupportedMediaType);

			// TODO: Valid name regular expression (A-Za-z0-9\!\*\'\(\)\,\$\-_\.\+)
			ItemInstance newFolder = new ItemInstance();
			newFolder.Name = itemUri.AbsoluteUri.Substring(itemUri.AbsoluteUri.LastIndexOf('/') + 1);
			// an absolute URI may contain a query string... we don't want that.
			if (newFolder.Name.Contains('?'))
				newFolder.Name = newFolder.Name.Substring(newFolder.Name.IndexOf('?'));
			newFolder.Name = Uri.UnescapeDataString(newFolder.Name);
			newFolder.ParentId = parentItem.Id;
			newFolder.Specification = parentItem.Specification;
			newFolder.Published = true;
			newFolder.MimeType = "application/x-folder";
			newFolder.CreatedBy = context.User.Identity.Name;
			item = handler.ItemRequest(context.User, RequestTypes.SetItem, parentUri, newFolder, LoadOptions.ItemCreateReference).FirstOrDefault();

			if (item == null)
				throw new Http.ServerException(ServerErrorStatus.InternalServerError, "Could not create item??");
			context.Response.SetStatus((int)SuccessStatus.Created, "");
			context.Response.SetItemHeaders(item, HttpCacheability.NoCache);
		}
	}
}
